<?php

namespace Aitels\Design;

use Illuminate\Support\Str;
use Illuminate\Database\Schema\Blueprint;

/**
 * 对Provider提供的定义进行一些处理(去除空格、补充默认值等)
 *
 * Class DefinitionProcessor
 * @package Aitels\Design
 */
class DefinitionProcessor
{
    protected $default;
    protected $bluePrintReflection;

    public function __construct($default)
    {
        $this->default = $default;
        $this->bluePrintReflection = new \ReflectionClass(Blueprint::class);
    }

    public function process($definition)
    {

        $definition['columns'] = collect($definition['columns'])
            //过滤 excel 空行
            ->reject(function ($column) {
                return collect($column)->reduce(function ($carry, $value) {
                    return !$value && $carry;
                }, true);
            })
            //trim 空格
            ->map(function ($column) {

                return collect($column)->map(function ($value, $key) {
                    return is_string($value) ? trim($value) : $value;
                })->all();
            })
            //检查字段类型是否合法
            ->each(function ($column) {
                $this->assertTypeExist($column);
            })
            //字段非主键且未定义默认值时我们补充默认值
            ->map(function ($column) {
                //如果是主键我们确保他不能设置默认值
                if ($column['primary']) {
                    $column['default'] = null;
                } //如果是主键我们确保他不能设置默认值
                else {
                    $type = strtolower($column['type']);
                    $default = $column['default'];
                    switch (true) {
                        case Str::contains($type, 'integer'):
                            $column['default'] = $default ? $default : $this->default['integer'];
                            break;
                        case Str::contains($type, ['string']):
                            $column['default'] = $default ? $default : $this->default['string'];
                            break;
                        case Str::contains($type, ['timestamp']):
                            if ($column['name'] === 'deleted_at') { //兼容laravel的软删除行为
                                $column['nullable'] = true;
                                $column['default'] = null;
                            } else {
                                $column['default'] = $default ? $default : $this->default['timestamp'];
                            }
                            break;
                        case Str::contains($type, ['boolean']):
                            $column['default'] = $default ? $default : $this->default['bool'];
                            $column['type'] = 'tinyInteger';//布尔字段我们使用tinyInteger存储
                            break;
                        case Str::contains($type, ['decimal']):
                            $column['default'] = $default ? $default : $this->default['decimal'];
                            break;
                    }
                }
                return $column;
            })
            ->map(function ($column) {
                if (Str::contains($column['type'], ['text'])) {
                    $column['nullable'] = true;
                }
                return $column;
            })
            ->all();


        return $definition;
    }


    public function assertTypeExist($column)
    {
        $type=$column['type'];
        $reflection = new \ReflectionClass('Illuminate\Database\Schema\Blueprint');
        if (!$this->bluePrintReflection->hasMethod($type))
            throw new \Exception("字段[{$column['name']}]类型不正确 : '{$type}'");
    }

}
